/**
 * Dynamically create tooltips, append specific content from different medians, and display at certain positions.
 *
 * @copyright   2010, Blizzard Entertainment, Inc
 * @class       Tooltip
 * @requires    Page
 * @example
 *
 *      onmouseover="Tooltip.show(this, 'This is the tooltip text!');"
 *
 */

var Tooltip = {

    /**
     * The current tooltip object and its markup
     */
    wrapper: null,

    /**
     * Content within the tooltip
     */
    contentCell: null,

    /**
     * Cached results from the AJAX responses
     */
    cache: {},

    /**
     * Flag storing intialization status of tooltip
     */
    initialized: false,

	/**
	 * Is the mouse currently hovering over the node?
	 */
	currentNode: null,

	/**
	 * Default options
	 */
	options: {
		ajax: false,
		className: false,
		location: 'topRight',
		useTable: false
	},

    /**
     * Initialize the tooltip markup and append it to document.
     *
     * @constructor
     */
    initialize: function() {
		var tooltipDiv = $('<div/>').addClass('ui-tooltip').appendTo("body");

		if (!Tooltip.options.useTable) {
			Tooltip.contentCell = $('<div/>').addClass('tooltip-content').appendTo(tooltipDiv);

		} else {
			var tooltipTable = $("<table>", {
				cellspacing: 0,
				cellpadding: 0
			}).appendTo(tooltipDiv);

			var emptyCell    = $('<td>').attr("valign", "top").text(" ");
			var emptyRow     = $('<tr>');
			var contentCell = emptyCell.clone();

			tooltipTable
				.append(
					emptyRow.clone()
					.append(emptyCell.clone().addClass("top-left"))
					.append(emptyCell.clone().addClass("top-center"))
					.append(emptyCell.clone().addClass("top-right"))
				)
				.append(
					emptyRow.clone()
					.append(emptyCell.clone().addClass("middle-left"))
					.append(contentCell.addClass("middle-center"))
					.append(emptyCell.clone().addClass("middle-right"))
				)
				.append(
					emptyRow.clone()
					.append(emptyCell.clone().addClass("bottom-left"))
					.append(emptyCell.clone().addClass("bottom-center"))
					.append(emptyCell.clone().addClass("bottom-right"))
				);

			Tooltip.contentCell = contentCell;
		}

		// Assign to reference later
		Tooltip.wrapper = tooltipDiv;
		Tooltip.initialized = true;
	},

	/**
	 * Bind a mouse over to all tooltips in the page. Will only display the title of the element.
	 * Will first detect data-tooltip and then the tooltip attribute.
	 *
	 * @param string query
	 * @param object options
	 */
	bind: function(query, options) {
		query = $(query);
		query.unbind('mouseover.tooltip');
		query.bind('mouseover.tooltip', function(e) {
			var title = $(this).data('tooltip') || this.title;

			if (title)
				Tooltip.show(this, title, options);
		});
	},

    /**
     * Grab the content for the tooltip, then pass it on to be positioned.
     *
     * @param object node
     * @param mixed content
     * @param object options - className, ajax, location
     */
    show: function(node, content, options) {
		if (!Tooltip.wrapper)
			Tooltip.initialize();

		if (options === true)
			options = { ajax: true };
		else
			options = options || {};

		options = $.extend({}, Tooltip.options, options);

		Tooltip.currentNode = node = $(node);

		// Update trigger node
        node.mouseout(function() {
        	Tooltip.hide();
			Tooltip.currentNode = null;

			if (options.className)
				Tooltip.wrapper.removeClass(options.className);
        });

		// Update values
		if (!Tooltip['_'+ options.location])
			options.location = Tooltip.options.location;

		// Left align tooltips in the right half of the screen
		if (options.location == Tooltip.options.location && node.offset().left > $(window).width() / 2)
			options.location = 'topLeft';

		if (options.className)
			Tooltip.wrapper.addClass(options.className);

		if (typeof content == 'object') {
			// Content: DOM node created w/ jQuery
			Tooltip.position(node, content, options.location);

		} else if (typeof content == 'string') {
			// Content: AJAX
			if (options.ajax) {
				if (Tooltip.cache[content]) {
					Tooltip.position(node, Tooltip.cache[content], options.location);
				} else {
					$.ajax({
						type: "GET",
						url: Core.baseUrl + content,
						dataType: "html",
						success: function(data, status) {
							if(Tooltip.currentNode == node) {
								Tooltip.cache[content] = data;
								Tooltip.position(node, data, options.location);
							}
						},
						error: function() {
							if(Tooltip.currentNode == node) {
								Tooltip.position(node, Msg.ui.unexpectedError, options.location);
							}
						}
					});
				}

			// Content: Copy content from the specified DOM node (referenced by ID)
			} else if (content.substr(0, 1) == '#') {
				Tooltip.position(node, $(content).html(), options.location);

			// Content: Text
			} else {
				Tooltip.position(node, content, options.location);
			}
		}
    },

    /**
     * Hide the tooltip.
     */
	hide: function() {
		if (!Tooltip.wrapper)
			return;

		Tooltip.wrapper.hide();
		Tooltip.wrapper.unbind('mousemove.tooltip');
	},

    /**
     * Position the tooltip at specific coodinates.
     *
     * @param object node
     * @param mixed content
	 * @return object
     */
    position: function(node, content, location) {
		if (!Tooltip.currentNode)
			return;

		if(typeof content == 'string')
	        Tooltip.contentCell.html(content);
		else
			Tooltip.contentCell.empty().append(content);

        var width = Tooltip.wrapper.outerWidth();
        var height = Tooltip.wrapper.outerHeight();
		var coords = Tooltip['_'+ location](width, height, node);

		if (coords) {
			Tooltip.wrapper
				.css("left", coords.x +"px")
				.css("top",  coords.y +"px")
				.show();
		}
    },

	/**
	 * Position at the mouse cursor.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 */
	_mouse: function(width, height, node) {
		node.bind('mousemove.tooltip', function(e) {
			Tooltip.wrapper
				.css("left", (e.pageX + 10) +"px")
				.css("top",  (e.pageY + 10) +"px")
				.show();
		});
	},

	/**
	 * Position at the top left.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_topLeft: function(width, height, node) {
		var offset = node.offset();

		// Set x and y
        var x = offset.left - width;
        var y = offset.top - height;

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the top center.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_topCenter: function(width, height, node) {
		var offset = node.offset();
        var nodeWidth = node.outerWidth();

		// Set x and y
        var x = offset.left + ((nodeWidth / 2) - (width / 2));
        var y = offset.top - height;

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the top right.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_topRight: function(width, height, node) {
		var offset = node.offset();
        var nodeWidth = node.outerWidth();

		// Set x and y
        var x = offset.left + nodeWidth;
        var y = offset.top - height;

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the middle left.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_middleLeft: function(width, height, node) {
		var offset = node.offset();
		var nodeHeight = node.outerHeight();

		// Set x and y
        var x = offset.left - width;
        var y = (offset.top + (nodeHeight / 2)) - (height / 2);

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the middle right.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_middleRight: function(width, height, node) {
		var offset = node.offset();
        var nodeWidth = node.outerWidth();
		var nodeHeight = node.outerHeight();

		// Set x and y
        var x = offset.left + nodeWidth;
        var y = (offset.top + (nodeHeight / 2)) - (height / 2);

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the bottom left.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_bottomLeft: function(width, height, node) {
		var offset = node.offset();
		var nodeHeight = node.outerHeight();

		// Set x and y
        var x = offset.left - width;
        var y = offset.top + nodeHeight;

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the bottom center.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_bottomCenter: function(width, height, node) {
		var offset = node.offset();
        var nodeWidth = node.outerWidth();
		var nodeHeight = node.outerHeight();

		// Set x and y
        var x = offset.left + ((nodeWidth / 2) - (width / 2));
        var y = offset.top + nodeHeight;

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Position at the bottom right.
	 *
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_bottomRight: function(width, height, node) {
		var offset = node.offset();
        var nodeWidth = node.outerWidth();
		var nodeHeight = node.outerHeight();

		// Set x and y
        var x = offset.left + nodeWidth;
        var y = offset.top + nodeHeight;

		return Tooltip._checkViewport(x, y, width, height, node);
	},

	/**
	 * Makes sure the tooltip appears within the viewport.
	 *
	 * @param int x
	 * @param int y
	 * @param int width
	 * @param int height
	 * @param object node
	 * @return object
	 */
	_checkViewport: function(x, y, width, height, node) {
		var offset = node.offset();

		// Greater than x viewport
		if ((x + width) > Page.dimensions.width)
			x = (offset.left - width);

		// Less than x viewport
		else if (x < 0)
			x = 15;

		// Greater than y viewport
		if ((y + height) > (Page.scroll.top + Page.dimensions.height))
			y = y - ((y + height) - (Page.scroll.top + Page.dimensions.height));

		// Node on top of viewport scroll
		else if ((offset.top - 100) < Page.scroll.top)
			y = offset.top + node.outerHeight();

		// Less than y viewport scrolled
		else if (y < Page.scroll.top)
			y = Page.scroll.top + 15;

		// Less than y viewport
		else if (y < 0)
			y = 15;

		return {
			x: x,
			y: y
		};
	}

};
